home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / MAIN.C < prev    next >
Text File  |  1993-10-18  |  34KB  |  1,502 lines

  1. /* Main network program - provides both client and server functions */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <alloc.h>
  6. #include <time.h>
  7. #include "global.h"
  8. #include <fcntl.h>
  9. #include <dos.h>
  10. #include <io.h>
  11. #include <conio.h>
  12. #include <ctype.h>
  13. #include <dir.h>
  14. #include <sys\stat.h>
  15. #include "config.h"
  16. #ifdef    ANSIPROTO
  17. #include <stdarg.h>
  18. #endif
  19. #include "files.h"
  20. #include "mbuf.h"
  21. #include "socket.h"
  22. #include "iface.h"
  23. #include "devparam.h"
  24. #include "ftp.h"
  25. #include "telnet.h"
  26. #include "remote.h"
  27. #include "session.h"
  28. #include "cmdparse.h"
  29. #include "ax25.h"
  30. #include "arp.h"
  31. #include "kiss.h"
  32. #include "enet.h"
  33. #include "timer.h"
  34. #include "proc.h"
  35. #include "tty.h"
  36. #include "daemon.h"
  37. #include "domain.h"
  38. #include "usock.h"
  39. #include "netrom.h"
  40. #include "ip.h"
  41. #include "tcp.h"
  42. #ifdef UDP
  43. #include "udp.h"
  44. #endif
  45. #include "hardware.h"
  46. #include "commands.h"
  47. #include "asy.h"
  48. #include "slip.h"
  49. #include "trace.h"
  50. #ifdef SCC
  51. #include "scc.h"
  52. #endif
  53. #ifdef VANESSA
  54. #include "vanessa.h"
  55. #endif
  56. #include "event.h"
  57.  
  58. unsigned int _stklen = 8192;
  59.  
  60. static char Escape = 0x1b;            /* default escape character is ESC */
  61.  
  62. char Badhost[] = "Unknown host %s\n";
  63. char Invcall[] = "Invalid call %s\n";
  64.  
  65. char Hostname[30];
  66.  
  67. static int Logging = FALSE;
  68. static int Logwait = 0;
  69. static struct proc *Cmdpp, *statp;
  70. struct proc *Display;
  71. struct session *Command, *Trace;
  72. static time_t StartTime;            /* Time that NOS was started */
  73. int32 currtime = 0;
  74. char uploadstatus = 1;
  75.  
  76. int Niface = 0;                        /* Number of Ifaces */
  77. #ifdef LZW
  78. int16 Lzwbits = LZWBITS;
  79. int Lzwmode = LZWCOMPACT;
  80. #endif
  81.  
  82. static void near loadfile __ARGS((void));
  83.  
  84. static char version[] =    "\nKA9Q NOS based %s (%s)\n"
  85.                         "Copyright 1993 by Phil Karn (KA9Q), "
  86.                         "WAMPES parts by DK5SG, and others.\n\n";
  87.  
  88. #define    NORMALL    48
  89. #define NORMALH    23
  90. #define NORMALS 113
  91. #define INVERS    30
  92. #define    RED        71
  93. #define COMMON    7
  94. #define PANIC   206
  95.  
  96. static int normal = NORMALL;        /* used for statusline */
  97. static int normalh = NORMALH;
  98. static int normals = NORMALS;
  99. static int invers = INVERS;
  100. static int red = RED;
  101. static int common = COMMON;
  102. static int panic = PANIC;
  103. static void dostatustimer __ARGS((void));
  104. struct timer Statustimer;
  105. static unsigned char Currmode;
  106.  
  107. #undef RESETTIMER
  108.  
  109. #ifdef RESETTIMER
  110. /* Timer card - developed by DL3YDN.9203xx
  111.  * code is compiled in when defining RESETTIMER
  112.  *
  113.  * Register des Timers 8253
  114.  */
  115. #define TIMCTRL    0x213
  116. #define TIMER0    0x210
  117. #define TIMER1    0x211
  118. #define TIMER2    0x212
  119.  
  120. /* Register des I/O Bausteins 8255 */
  121. #define IOCTRL    0x217
  122. #define PORTA    0x214
  123. #define PORTB    0x215
  124. #define PORTC    0x216
  125.  
  126. static void near inittim __ARGS((void));
  127. #endif
  128.  
  129. unsigned char Nrows = NROWS;    /* extra defined for 43/50 line mode - DB3FL */
  130.  
  131. int
  132. main(int argc,char **argv)
  133. {
  134.     struct daemon *tp;
  135.     struct mbuf *bp;
  136.     int c, i;
  137.     char *startfile[3], root[MAXPATH];
  138.     struct time sttime;
  139.     struct text_info r;
  140.  
  141.     delay(0);
  142.     randomize();
  143.  
  144.     gettextinfo(&r);
  145.     Currmode = r.currmode;
  146.  
  147.     directvideo = 1;
  148.     *root = '\0';
  149.  
  150.     do {
  151.         optarg = NULLCHAR;
  152.         c = getopt(argc,argv,"s:d:be");
  153.         switch(c){
  154.         case 's':    /* Number of sockets */
  155.             Nusock = atoi(optarg);
  156.             break;
  157.         case 'd':    /* Root directory for various files */
  158.             strcpy(root,optarg);
  159.             break;
  160. #ifdef    __TURBOC__
  161.         case 'b':    /* Use BIOS for screen output */
  162.             directvideo = 0;
  163.             break;
  164. #endif
  165. #ifdef __CPLUSPLUS
  166.         case 'e':
  167.             textmode(C4350);
  168.             gettextinfo(&r);
  169.             break;
  170. #endif
  171.         case '?':
  172.             printf("aborted...\007\r\n");
  173.             exit(1);
  174.         }
  175.     } while (c != EOF);
  176.  
  177.     initroot(root);
  178.  
  179.     Nrows = r.screenheight;
  180.  
  181. #ifdef RESETTIMER
  182.     inittim();
  183. #endif
  184.  
  185.     if(getenv("TZ") == NULL) {
  186.         putenv("TZ=UTC-1");
  187.     }
  188.     tzset();
  189.  
  190.     currtime = StartTime = time(&StartTime);
  191.  
  192.     gettime(&sttime);
  193.     EMinute = sttime.ti_hour * 60 + sttime.ti_min;
  194.  
  195.     ioinit();
  196.     kinit();
  197.     sockinit();
  198.  
  199.     Cmdpp = mainproc("cmdintrp");
  200.     window(1,3,80,Nrows);
  201.  
  202.     /*-------------------------------------------------------------------*
  203.     * initialize name cache DK5DC                                        *
  204.     *--------------------------------------------------------------------*/
  205.     cache = cxallocw(sizeof(Cache),(Dcache_size + 2));
  206.  
  207.     Sessions = cxallocw(Nsessions,sizeof(struct session));
  208.     Trace = newsession("Trace",TRACESESSION,SPLIT);
  209.  
  210.     Lastcurr = Command = newsession("cmd interpreter",COMMAND,SWAP);
  211.     Command->flowmode = Cooked;        /* set 'more' paging on command screen */
  212.     Trace->input = Command->input;
  213.     Display = newproc("display",512,display,0,NULLCHAR,NULL,0);
  214.  
  215.     /* Start background Daemons */
  216.     for(tp = Daemons; tp->name != NULLCHAR; tp++) {
  217.         newproc(tp->name,tp->stksize,tp->fp,0,NULLCHAR,NULL,0);
  218.         for(i = 0; i < 1000; i++) ;
  219.     }
  220.     /* allocates buffer for the trace screen */
  221.     swapscreen(Trace,NULLSESSION);
  222.  
  223.     tprintf(version,Version,__DATE__);
  224.  
  225.     *Hostname = '\0';
  226.  
  227.     startfile[1] = strxdup(optind < argc ? argv[optind] : Startup);
  228.     dosource(1,startfile,NULL);
  229.     xfree(startfile[1]);
  230.  
  231.     if(Niface) {
  232.         loadfile();
  233.     }
  234.     uploadstatus = 0;
  235.     Command->flag = 1;
  236.  
  237.     /* Now loop forever, processing commands */
  238.     for(;;){
  239.         if(Current == Command && Command->flag) {    /* DK5DC */
  240.             if(*Hostname) {
  241.                 tprintf("%s> ",Hostname);
  242.             } else {
  243.                 tputs("net> ");
  244.             }
  245.             Command->flag = 0;
  246.             tflush();
  247.         }
  248.         pwait(NULL);
  249.  
  250.         if(recv_mbuf(Command->input,&bp,0,NULLCHAR,0) != -1){
  251.             cmdparse(Cmds,bp->data,Lastcurr);
  252.             free_p(bp);
  253.         }
  254.     }
  255. }
  256.  
  257. /* Keyboard input process */
  258. void
  259. keyboard(int i,void *v1,void *v2)
  260. {
  261.     int c, j, k;
  262.     struct mbuf *bp;
  263.     struct session *sp;
  264.  
  265.     /* Keyboard process loop */
  266.     for(;;) {
  267.         if((c = kbread()) == Escape && Escape != 0) {
  268.             c = -2;
  269.         }
  270.         if(c == -2 && Current != Command) {
  271.             /* Save current tty mode and set cooked */
  272.             swapscreen(Current,Command);
  273.             Lastcurr = Current;
  274.             Current = Command;
  275.  
  276.             if(Command->flag) {
  277.                 if(*Hostname) {
  278.                     tprintf("%s> ",Hostname);
  279.                 } else {
  280.                     tputs("net> ");
  281.                 }
  282.                 Command->flag = 0;
  283.                 tflush();
  284.             }
  285.             /* set 'more' paging on command screen */
  286.             Command->flowmode = Cooked;
  287.         }
  288.         if(c < -2) {            /* F1 to F10 pressed */
  289.             if(c == -13) {      /* F9 handled here */
  290.                 if(Current != Trace) {
  291.                     swapscreen(Current,Trace);
  292.                     Lastcurr = Current;
  293.                     Current = Trace;
  294.                     Trace->flowmode = Raw;
  295.                 } else {
  296.                     swapscreen(Trace,Lastcurr);
  297.                     Current = Lastcurr;
  298.                     Lastcurr = Trace;
  299.                 }
  300.             } else {
  301.                 for(sp = Sessions, j = 1, k = abs(c); sp < &Sessions[Nsessions]; sp++) {
  302.                     if(sp->type != COMMAND) {
  303.                         j++;
  304.                         if(sp->type != FREE && j == k) {
  305.                             swapscreen(Current,sp);
  306.                             Lastcurr = Current;
  307.                             Current = sp;
  308.                             break;
  309.                         }
  310.                     }
  311.                 }
  312.             }
  313.         }
  314.         Current->row = (Current->split) ? Nrows - 5 : Nrows - 3;
  315.         psignal(&Current->row,1);
  316.  
  317.         if(c >= 0) {
  318.             /* If the screen driver was in morewait state, this char
  319.              * has woken him up. Toss it so it doesn't also get taken
  320.              * as normal input. If the char was a command escape,
  321.              * however, it will be accepted; this gives the user
  322.              * a way out of lengthy output.
  323.              */
  324.             if(!Current->morewait) {
  325.                 if((bp = ttydriv(Current,c)) == NULLBUF){
  326.                     if(Current->lwrap >= 30
  327.                       && len_p(Current->ttystate.line) > Current->lwrap
  328.                       && Command != Current
  329.                       && (c == 32 || c == '-')) {
  330.                         bp = ttydriv(Current,13);
  331.                         send_mbuf(Current->input,bp,0,NULLCHAR,0);
  332.                     }
  333.                 } else {
  334.                     send_mbuf(Current->input,bp,0,NULLCHAR,0);
  335.                 }
  336.             }
  337.         }
  338.     }
  339. }
  340.  
  341. /* Standard commands called from main */
  342.  
  343. /* exit cmd now give the value of argv[1] as the errorlevel to DOS.
  344.  * values greater than 255 are cut to a maximum of 255.
  345.  */
  346. int
  347. doexit(int argc,char **argv,void *p)
  348. {
  349.     int arg = atoi(argv[1]);
  350.  
  351. #ifdef RESETTIMER
  352.     outport(PORTC,0x00);                  /* Disable Watchdog */
  353. #endif
  354.  
  355.     uploadstatus = 1;
  356.  
  357.     while(arg > 256) {
  358.         arg -= 256;
  359.     }
  360.     if(arg < 250) {
  361.         int i;
  362.  
  363.         reset_all();
  364.         shuttrace();
  365.  
  366.         for(i = 0; i < 100; i++) {
  367.             pwait(NULL);
  368.         }
  369.     }
  370.     log(-1,9983,"Shutdown %s Exit code %d",ctime(&currtime),arg);
  371.  
  372.     iostop();
  373.  
  374.     /* restore video mode */
  375.     textmode(Currmode);
  376.  
  377.     exit(arg);
  378.     return 0;                            /* To satisfy lint */
  379. }
  380.  
  381. int
  382. dohostname(int argc,char **argv,void *p)
  383. {
  384.     if(argc < 2) {
  385.         tprintf("%s\n",Hostname);
  386.     } else {
  387.         sprintf(Hostname,"%.27s",argv[1]);
  388.     }
  389.     return 0;
  390. }
  391.  
  392. int
  393. dolog(int argc,char **argv,void *p)
  394. {
  395.     int OldLogging = Logging;
  396.  
  397.     setbool(&Logging,"Logging",argc,argv);
  398.  
  399.     if(OldLogging == FALSE && Logging == TRUE) {
  400.         log(-1,9983,"Startup %s",ctime(&StartTime));
  401.     }
  402.     return 0;
  403. }
  404.  
  405. int
  406. dohelp(int argc,char **argv,void *p)
  407. {
  408.     if(argc < 2) {
  409.         int i;
  410.         struct cmds *cmdp;
  411.  
  412.         tputs("Main commands:\n");
  413.  
  414.         for(i = 0, cmdp = Cmds; cmdp->name != NULLCHAR; cmdp++) {
  415.             if(strlen(cmdp->name) > 0) {
  416.                 tprintf("%-15.15s%s",cmdp->name,(i == 4) ? "\n" : "");
  417.                 i = (i + 1) % 5;
  418.             }
  419.         }
  420.         if(i) {
  421.             tputs("\n");
  422.         }
  423.     } else {
  424.         gethelp(9983,Curproc->output,argv[1]);
  425.     }
  426.     return 0;
  427. }
  428.  
  429. /* Manipulate I/O device parameters */
  430. int
  431. doparam(int argc,char **argv,void *p)
  432. {
  433.     int param, set;
  434.     struct iface *ifp;
  435.     int32 val = -1;
  436.  
  437.     if((ifp = if_lookup(argv[1])) == NULLIF) {
  438.         tprintf(Badif,argv[1]);
  439.         return -1;
  440.     }
  441.     if(ifp->ioctl != 0) {
  442.         if(argc < 3) {
  443.             for(param = 1; param <= 16; param++) {
  444.                 if((val = (*ifp->ioctl)(ifp,param,FALSE,0)) != -1)
  445.                     tprintf("%s: %ld\n",parmname(param),val);
  446.             }
  447.             return 0;
  448.         }
  449.         if((param = devparam(argv[2])) == -1) {
  450.             tprintf("Unknown parameter %s\n",argv[2]);
  451.             return -1;
  452.         }
  453.         if(param == PARAM_STRING) {
  454.             struct mbuf *hbp;
  455.             int i;
  456.             char *cp;
  457.  
  458.             /* Allocate space for arg bytes */
  459.             argc -= 3;
  460.             argv += 3;
  461.             hbp = alloc_mbuf(argc);
  462.             hbp->cnt = argc;
  463.             hbp->next = NULLBUF;
  464.             for(i = 0, cp = hbp->data; i < argc; ) {
  465.                 *cp++ = atoi(argv[i++]);
  466.             }
  467.             if((int)hbp->data[0] != PARAM_RETURN) {
  468.                 hbp->data[0] |= (ifp->port << 4);
  469.             }
  470.             if(ifp->port) {
  471.                 ifp->rawsndcnt++;
  472.                 ifp->lastsent = secclock();
  473.             }
  474.             /* Even more "raw" than kiss_raw */
  475.             slip_raw(Slip[ifp->xdev].iface,hbp);
  476.             return 0;
  477.         }
  478.         if(argc < 4) {
  479.             set = FALSE;
  480.             val = 0L;
  481.         } else {
  482.             set = TRUE;
  483.             val = atol(argv[3]);
  484.         }
  485.     }
  486.     if(val == -1 || (val = (*ifp->ioctl)(ifp,param,set,val)) < 0) {
  487.         tputs("Not supported\n");
  488.     } else if(set == FALSE) {
  489.         tprintf("%s: %ld\n",parmname(param),val);
  490.     }
  491.     return (int)val;
  492. }
  493.  
  494. #ifdef AX25
  495. /* Display or set IP interface control flags */
  496. int
  497. domode(int argc,char **argv,void *p)
  498. {
  499.     struct arp_tab *arp;
  500.     int32 addr;
  501.  
  502.     if((addr = resolve(argv[1])) == 0 || (arp = arp_lookup(ARP_AX25,addr)) == NULLARP) {
  503.         tprintf(Badhost,argv[1]);
  504.         return -1;
  505.     }
  506.     if(argc < 3) {
  507.         char *e = "", buf1[AXBUF];
  508.  
  509.         switch(arp->flags) {
  510.         case DATAGRAM_MODE:
  511.             e = "Datagram";
  512.             break;
  513.         case CONNECT_MODE:
  514.             e = "VC";
  515.             break;
  516.         case IPCAM_MODE:
  517.             e = "IPCAM";
  518.             break;
  519.         default:
  520.             e = "unknown";
  521.             return 0;
  522.         }
  523.         tprintf("%s (%s): Mode %s\n",
  524.             strupr(argv[1]),pax25(buf1,arp->hw_addr),e);
  525.         return 0;
  526.     } else {
  527.         struct arp_tab *ap;
  528.  
  529.         switch(argv[2][0]){
  530.         case 'd':
  531.             arp->flags = DATAGRAM_MODE;
  532.             break;
  533.         case 'v':
  534.         case 'c':
  535.             arp->flags = CONNECT_MODE;
  536.             break;
  537.         case 'i':
  538.             arp->flags = IPCAM_MODE;
  539.             break;
  540.         default:
  541.             tputs("Usage: mode <datagram|vc|ipcam>\n");
  542.             return -1;
  543.         }
  544.         for(ap = Arp_tab; ap != NULLARP; ap = ap->next) {
  545.             if(strcmp(arp->hw_addr,ap->hw_addr) == 0) {
  546.                 ap->flags = arp->flags;
  547.             }
  548.         }
  549.     }
  550.     return 0;
  551. }
  552. #endif
  553.  
  554. int
  555. doescape(int argc,char **argv,void *p)
  556. {
  557.     if(argc < 2){
  558.         tprintf("Escape char: CTRL-%c\n",Escape + 'A' - 1);
  559.         return 0;
  560.     }
  561.     if(iscntrl(*argv[1])) {
  562.         Escape = *argv[1];
  563.     }
  564.     return 0;
  565. }
  566.  
  567. #ifdef UDP
  568. /* Generate system command packet. Synopsis:
  569.  * remote [-p port#] [-k key] [-a hostname] <hostname> reset|exit|kickme
  570.  */
  571. int
  572. doremote(int argc,char **argv,void *p)
  573. {
  574.     struct sockaddr_in fsock;
  575.     int s, c, klen;
  576.     char *data = NULLCHAR, *cmd, *host, x, *key = NULLCHAR;
  577.     int16 len = 1;
  578.     int32 addr = 0;
  579.  
  580.     int16 port = IPPORT_REMOTE;    /* Set default */
  581.     optind = 1;        /* reinit getopt() */
  582.  
  583.     while((c = getopt(argc,argv,"a:p:k:s:")) != EOF){
  584.         switch(c){
  585.         case 'a':
  586.             if((addr = resolve(optarg)) == 0){
  587.                 tprintf(Badhost,optarg);
  588.                 return -1;
  589.             }
  590.             break;
  591.         case 'p':
  592.             port = atoi(optarg);
  593.             break;
  594.         case 'k':
  595.             key = strxdup(optarg);
  596.             klen = strlen(key);
  597.             break;
  598.         case 's':
  599.             Rempass = strxdup(optarg);
  600.             return 0;    /* Only set local password */
  601.         }
  602.     }
  603.     if(optind > argc - 2){
  604.         tputs("Insufficient args\n");
  605.         goto quit;
  606.     }
  607.     host = argv[optind++];
  608.     cmd = argv[optind];
  609.     if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  610.         tputs(Nosocket);
  611.         goto quit;
  612.     }
  613.     /* Did the user include a password or kickme target? */
  614.     if(addr != 0 && cmd[0] == 'k')
  615.         len += sizeof(int32);
  616.  
  617.     if(key != NULLCHAR && (cmd[0] == 'r' || cmd[0] == 'e'))
  618.         len += klen;
  619.  
  620.     if(len == 1) {
  621.         data = &x;
  622.     } else {
  623.         data = mxallocw(len);
  624.     }
  625.  
  626.     fsock.sin_family = AF_INET;
  627.     if((fsock.sin_addr.s_addr = resolve(host)) == 0){
  628.         tprintf(Badhost,host);
  629.         goto cleanup;
  630.     }
  631.     fsock.sin_port = port;
  632.  
  633.     switch(*cmd){
  634.     case 'r':
  635.         data[0] = SYS_RESET;
  636.         if(key != NULLCHAR)
  637.             sprintf(&data[1],"%.*s",klen,key);
  638.         break;
  639.     case 'e':
  640.         data[0] = SYS_EXIT;
  641.         if(key != NULLCHAR)
  642.             sprintf(&data[1],".*s",klen,key);
  643.         break;
  644.     case 'k':
  645.         data[0] = KICK_ME;
  646.         if(addr != 0)
  647.             put32(&data[1],addr);
  648.         break;
  649.     default:
  650.         tprintf("Unknown command %s\n",cmd);
  651.         goto cleanup;
  652.     }
  653.     /* Form the command packet and send it */
  654.     if(sendto(s,data,len,0,(char *)&fsock,SOCKSIZE) == -1) {
  655.         tprintf("sendto failed: %s\n",sys_errlist[errno]);
  656.     }
  657. cleanup:
  658.     close_s(s);
  659. quit:
  660.     if(data != &x)
  661.         xfree(data);
  662.     if(key != NULLCHAR)
  663.         xfree(key);
  664.     return 0;
  665. }
  666. #endif
  667.  
  668. int
  669. domore(int argc,char **argv,void *p)
  670. {
  671.     struct session *sp;
  672.     FILE *fp;
  673.     char buf[LINELEN];
  674.     int row = Nrows - 3;
  675.  
  676.     if((fp = Fopen(argv[1],READ_TEXT,0,1)) == NULLFILE) {
  677.         return -1;
  678.     }
  679.     if((sp = newsession(argv[1],MORE,SWAP)) == NULLSESSION) {
  680.         Fclose(fp);
  681.         tputs(Nosess);
  682.         return -1;
  683.     }
  684.     /* Put tty into raw mode so single-char responses will work */
  685.     sp->ttystate.echo = sp->ttystate.edit = 0;
  686.  
  687.     while(fgets(buf,LINELEN,fp) != NULL){
  688.         tputs(buf);
  689.         if(--row == 0){
  690.             row = keywait("--More--",0);
  691.             switch(row){
  692.             case -1:
  693.             case 'q':
  694.             case 'Q':
  695.                 goto done;
  696.             case '\n':
  697.             case '\r':
  698.                 row = 1;
  699.                 break;
  700. /*            case ' ':    */
  701.             default:
  702.                 row = Nrows - 3;
  703.             }
  704.         }
  705.     }
  706. done:
  707.     Fclose(fp);
  708.     keywait(NULLCHAR,1);
  709.     freesession(sp);
  710.     return 0;
  711. }
  712.  
  713. int
  714. dotail(int argc,char **argv,void *p)
  715. {
  716.     int handle, i;
  717.     unsigned line = 0, rdsize = 2000;
  718.     long length;
  719.     char buffer[2000];
  720.     static char Noread[] = "Can't read %s: %s\n";
  721.  
  722.     if((handle = open(argv[1],O_BINARY | O_RDONLY)) == -1) {
  723.         tprintf(Noread,argv[1],sys_errlist[errno]);
  724.         return -1;
  725.     }
  726.     length = filelength(handle);
  727.  
  728.     if (length > 2000) {
  729.         length -= 2000;
  730.     } else {
  731.         rdsize = (int)length;
  732.         length = 0;
  733.     }
  734.  
  735.     lseek(handle,length,SEEK_SET);
  736.     if(read(handle,buffer,rdsize) == -1) {
  737.         tprintf(Noread,argv[1],sys_errlist[errno]);
  738.         close(handle);
  739.         return -1;
  740.     }
  741.  
  742.     for(i = rdsize - 1; i > 0; i--) {
  743.         if(buffer[i] == '\n')
  744.             line++;
  745.         if(line == Nrows - 7)
  746.             break;
  747.     }
  748.     for (; i < rdsize; i++) {
  749.         usputc(Curproc->output,buffer[i]);
  750.     }
  751.     tputs("\n");
  752.     close(handle);
  753.     return 0;
  754. }
  755.  
  756. /* Log messages of the form
  757.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  758.  */
  759. #if    defined(ANSIPROTO)
  760. void
  761. log(int s,int16 protocol,char *fmt, ...)
  762. {
  763.     FILE *Logfp;
  764.     char buf[MAXPATH];
  765.  
  766.     if(Logging == FALSE)
  767.         return;
  768.  
  769.     semwait(&Logwait,1);
  770.  
  771.     sprintf(buf,"%s/%s.log",EtcRoot,tcp_port(protocol));
  772.  
  773.     if((Logfp = Fopen(buf,APPEND_TEXT,0,0)) != NULLFILE) {
  774.         va_list ap;
  775.         struct sockaddr fsocket;
  776.         int i = SOCKSIZE;
  777.  
  778.         char *cp = ctime(&currtime);
  779.         cp[24] = '\0';
  780.  
  781.         fputs(cp,Logfp);
  782.  
  783.         if(getpeername(s,(char *)&fsocket,&i) != -1)
  784.             fprintf(Logfp," %s",psocket(&fsocket));
  785.  
  786.         fputs(" - ",Logfp);
  787.         va_start(ap,fmt);
  788.         vfprintf(Logfp,fmt,ap);
  789.         va_end(ap);
  790.         fputs("\n",Logfp);
  791.  
  792.         Fclose(Logfp);
  793.     }
  794.     semrel(&Logwait);
  795. }
  796. #else
  797. /*VARARGS2*/
  798. void
  799. log(int s,int16 protocol,char *fmt,int arg1,int arg2,int arg3,int arg4,int arg5)
  800. {
  801.     FILE *Logfp;
  802.     char buf[MAXPATH];
  803.  
  804.     if(Logging == FALSE)
  805.         return;
  806.  
  807.     semwait(&Logwait,1);
  808.  
  809.     sprintf(buf,"%s/%s.log",EtcRoot,tcp_port(protocol));
  810.  
  811.     if((Logfp = Fopen(buf,APPEND_TEXT,0,0)) != NULLFILE) {
  812.         va_list ap;
  813.         struct sockaddr fsocket;
  814.         int i = SOCKSIZE;
  815.  
  816.         char *cp = ctime(&currtime);
  817.         cp[24] = '\0';
  818.  
  819.         fputs(cp,Logfp);
  820.  
  821.         if(getpeername(s,(char *)&fsocket,&i) != -1)
  822.             fprintf(Logfp," %s",psocket(&fsocket));
  823.  
  824.         fputs(" - ",Logfp);
  825.         fprintf(Logfp,fmt,arg1,arg2,arg3,arg4,arg5);
  826.         fputs("\n",Logfp);
  827.  
  828.         Fclose(Logfp);
  829.     }
  830.     semrel(&Logwait);
  831. }
  832. #endif
  833.  
  834. int
  835. dosource(int argc,char **argv,void *p)
  836. {
  837.     FILE *fp;
  838.  
  839.     /* Read command source file */
  840.     if((fp = Fopen(argv[1],READ_TEXT,0,1)) != NULLFILE) {
  841.         int linenum = 0;
  842.         char inbuf[LINELEN], intmp[LINELEN];
  843.  
  844.         while(fgets(inbuf,LINELEN,fp) != NULLCHAR){
  845.             linenum++;
  846.             if(*inbuf == '#') {
  847.                 continue;
  848.             }
  849.             strcpy(intmp,inbuf);
  850.             if(cmdparse(Cmds,inbuf,0) < 0) {
  851.                 tprintf("ERROR - line %d:\n%s",linenum,intmp);
  852.             }
  853.             pwait(NULL);
  854.         }
  855.         Fclose(fp);
  856.     }
  857.     return 0;
  858. }
  859.  
  860. #ifdef    __TURBOC__
  861. /*
  862.  * Fstat utility code.
  863.  * Converted to go into NOS by Kelvin Hill - G1EMM  April 9, 1990
  864.  */
  865.  
  866. extern unsigned char _osmajor;
  867.  
  868. /* Make a copy of a string pointed to by a far pointer */
  869. static char * near
  870. localcopy(char far *s)
  871. {
  872.     char localstring[256], *l = localstring, far *p = s;
  873.  
  874.     int i = 0;
  875.  
  876.     while (*p != NULL && i++ < 255) {
  877.         *l++ = *p++;
  878.     }
  879.     *l = '\0';
  880.     return localstring;
  881. }
  882.  
  883. /*
  884.  * Return a near pointer to a character string with the full path name of the
  885.  * program whose PSP is given in the argument.  If the argument is invalid,
  886.  * this may return gibberish but I don't know how to tell Offset 0x2C in the
  887.  * PSP in the segment address of the environment of a program.  Beyond the
  888.  * last environment string is a null marker, a word count (usually 1), then
  889.  * the full pathname of the owner of the environment This only works for DOS
  890.  * 3+
  891.  */
  892. static char * near
  893. progname(unsigned int pid)
  894. {
  895.     /* find the parent process psp at offset 0x16 of the psp */
  896.     unsigned ppid = *(unsigned far *) MK_FP(pid, 0x16);
  897.  
  898.     /* find the environment at offset 2Ch of the psp */
  899.     unsigned far *envsegptr = (unsigned far *)MK_FP(pid, 0x2C);
  900.     char far *envptr = (char far *)MK_FP(*envsegptr, 0);
  901.  
  902.     /*
  903.      * Make a pointer that contains the size of the environment block.
  904.      * Must point back one paragraph (to the environments MCB plus three
  905.      * bytes forward (to the MCB block size field).
  906.      */
  907.     unsigned far *envsizeptr = (unsigned far *)MK_FP(*envsegptr - 1, 0x3);
  908.     unsigned envsize = *envsizeptr * 16;    /* x 16 turns it into bytes */
  909.  
  910.     while(envsize > 0) {
  911.         /* search for end of environment block, or NULL */
  912.         while(--envsize && *envptr++);
  913.  
  914.         /*
  915.          * Now check for another NULL immediately following the first
  916.          * one located and a word count of 0001 following that.
  917.          */
  918.         if(!*envptr && *(unsigned far *)(envptr + 1) == 0x1) {
  919.             envptr += 3;
  920.             break;
  921.         }
  922.     }
  923.     return (envsize > 0) ? localcopy(envptr) : (pid == ppid) ? "-shell-" : "unknown";
  924. }
  925.  
  926. static int near
  927. dofstat(void)
  928. {
  929.     union REGS regs;
  930.     struct SREGS segregs;
  931.     char far * pfiletab, far * pnext, far * name, far * plist, far * entry;
  932.     char file[13], ownername[9], ownerext[5];
  933.     int nfiles, i, numhandles, entrylen, heading = 0;
  934.     unsigned int access, devinfo, progpsp;
  935.     long length, offset;
  936.  
  937.     regs.h.ah = 0x52;    /* DOS list of lists */
  938.     intdosx(®s, ®s, &segregs);
  939.  
  940.     /* make a pointer to start of master list */
  941.     plist = (char far *)MK_FP(segregs.es,regs.x.bx);
  942.  
  943.     /* pointer to start of file table */
  944.     pfiletab = (char far *)MK_FP(*(int far *)(plist + 6),*(int far *)(plist + 4));
  945.  
  946.     switch (_osmajor) {
  947.     case 2:
  948.         entrylen = 40;    /* DOS 2.x */
  949.         break;
  950.     case 3:                /* DRDOS 6.0, too */
  951.         entrylen = 53;    /* DOS 3.x */
  952.         break;
  953.     case 4:
  954.     case 5:                /* DOS 5.0 */
  955.     case 6:                /* DOS 6.0 */
  956.         entrylen = 59;    /* DOS 4.x - I do not know what is in the */
  957.         break;            /* extra 6 bytes */
  958.     default:
  959.         return 1;
  960.     }
  961.  
  962.     for (;;) {
  963.         /* pointer to next file table */
  964.         pnext = (char far *)MK_FP(*(int far *)(pfiletab + 2),*(int far *)(pfiletab + 0));
  965.         nfiles = *(int far *)(pfiletab + 4);
  966. #ifdef MDEBUG
  967.         tprintf("\nFile table at %Fp entries for %d files\n", pfiletab, nfiles);
  968. #endif
  969.         for (i = 0; i < nfiles; i++) {
  970.             /* cycle through all files, quit when we reach an
  971.              * unused entry
  972.              */
  973.             entry = pfiletab + 6 + (i * entrylen);
  974.             if (_osmajor >= 3) {
  975.                 name = entry + 32;
  976.                 sprintf(file,"%.11s",localcopy(name));
  977.                 numhandles = *(int far *) (entry + 0);
  978.                 access = (int) *(char far *) (entry + 2);
  979.                 length = *(long far *) (entry + 17);
  980.                 offset = *(long far *) (entry + 21);
  981.                 devinfo = *(int far *) (entry + 5);
  982.                 progpsp = *(int far *) (entry + 49);
  983.             } else {
  984.                 name = entry + 4;
  985.                 sprintf(file,"%.11s",localcopy(name));
  986.                 numhandles = (int) *(char far *) (entry + 0);
  987.                 access = (int) *(char far *) (entry + 1);
  988.                 length = *(long far *) (entry + 19);
  989.                 offset = *(long far *) (entry + 36);
  990.                 devinfo = (int) *(char far *) (entry + 27);
  991.             }
  992.             if ((strlen(file) > 0) && (numhandles > 0) && !(devinfo & 0x80)) {
  993.                 if(!heading) {
  994.                     tputs("open files     length   offset hnd acc  PSP device type/owner\n");
  995.                     heading++;            /* header now printed */
  996.                 }
  997.                 tprintf("%8.8s.%3.3s %8ld %8ld  %2d ",file,&file[8],length,offset,numhandles);
  998.                 switch (access) {
  999.                 case 0:
  1000.                     tputs("r ");
  1001.                     break;
  1002.                 case 1:
  1003.                     tputs("w ");
  1004.                     break;
  1005.                 case 2:
  1006.                     tputs("rw");
  1007.                     break;
  1008.                 default:
  1009.                     tputs("  ");
  1010.                 }
  1011.                 if (_osmajor >= 3) {
  1012.                     tprintf("  %04X", progpsp);
  1013.                 } else {
  1014.                     tputs("  ----");
  1015.                 }
  1016.                 tprintf(" drive %c: ", 'A' + (devinfo & 0x1F));
  1017.  
  1018.                 if (devinfo & 0x8000) {
  1019.                     tputs("(network) ");
  1020.                 }
  1021.                 if (_osmajor >= 3) {
  1022.                     /*
  1023.                      * only DOS 3+ can find out
  1024.                      * the name of the program
  1025.                      */
  1026.                     fnsplit(progname(progpsp),NULL,NULL,ownername,ownerext);
  1027.                     tprintf("   [%s%s]",strlwr(ownername),strlwr(ownerext));
  1028.                 }
  1029.                 tputs("\n");
  1030.             }
  1031.             if(strlen(file) == 0) {
  1032.                 return 0;
  1033.             }
  1034.         }
  1035.         pfiletab = pnext;
  1036.     }
  1037. }
  1038. #endif
  1039.  
  1040. int
  1041. dostatus(int argc,char **argv,void *p)
  1042. {
  1043.     tprintf(version,Version,__DATE__);
  1044.     tprintf("Start time:   %s", ctime(&StartTime));
  1045.     tprintf("System time:  %s", ctime(&currtime));
  1046.     tprintf("Elapsed time: %s\n\n", tformat(secclock()));
  1047.  
  1048.     if(argc < 9) {
  1049. #ifdef MDEBUG
  1050.         tprintf("Load info:    CodeSeg=%04x, DataSeg=%04x\n\n", _CS, _DS);
  1051. #endif
  1052. #ifdef    __TURBOC__
  1053.         dofstat();        /* print status of open files */
  1054. #endif
  1055.     }
  1056.     return 0;
  1057. }
  1058.  
  1059. static void near
  1060. loadfile(void)
  1061. {
  1062.     FILE *fp;
  1063.     struct iface *ifp;
  1064.  
  1065. #ifdef NETROM
  1066.     extern int donrload __ARGS((void));
  1067.     extern int Nr_save;
  1068. #endif
  1069.  
  1070.     /* loading of ip-routes */
  1071.     if ((fp = Fopen(Iproutefile,READ_BINARY,0,1)) != NULLFILE) {
  1072.         struct ip_saverecord ipbuf;
  1073.  
  1074.         while(fread(&ipbuf,sizeof(struct ip_saverecord),1,fp)) {
  1075.             for(ifp = Ifaces; ifp; ifp = ifp->next) {
  1076.                 if(ifp->niface == ipbuf.niface) {
  1077.                     break;
  1078.                 }
  1079.             }
  1080.             if(ifp != NULLIF) {
  1081.                 if (ipbuf.gateway == 0xffffffffL) {
  1082.                     ipbuf.gateway = 0;
  1083.                 }
  1084.                 rt_add(ipbuf.target,ipbuf.bits,ipbuf.gateway,ifp,
  1085.                     ipbuf.metric,0,ipbuf.flags);
  1086.             }
  1087.         }
  1088.         Fclose(fp);
  1089.     }
  1090.  
  1091.     /* loading of arp-entries */
  1092.     if ((fp = Fopen(Arproutefile,READ_BINARY,0,1)) != NULLFILE) {
  1093.         struct arp_tab *p;
  1094.         struct arp_saverecord arpbuf;
  1095.         char hw_addr[MAXHWALEN];
  1096.  
  1097.         if(fgetc(fp) == ARP_FILE_VERSION) {        /* Version 3 required !!!! */
  1098.             while(fread(&arpbuf,sizeof(struct arp_saverecord),1,fp)) {
  1099.                 if (fread(hw_addr, arpbuf.hwalen, 1, fp)) {
  1100.                     if (arpbuf.hardware < NHWTYPES) {
  1101.                         if ((p = arp_add(arpbuf.ip_addr,arpbuf.hardware,
  1102.                           hw_addr,arpbuf.pub,arpbuf.flags)) != NULLARP) {
  1103.                             stop_timer(&p->timer);
  1104.                             set_timer(&p->timer,0L);
  1105.                         }
  1106.                     }
  1107.                 }
  1108.             }
  1109.         }
  1110.         Fclose(fp);
  1111.     }
  1112.  
  1113. #ifdef AX25
  1114.     /* loading of ax25-routes */
  1115.     if ((fp = Fopen(Axroutefile,READ_BINARY,0,1)) != NULLFILE) {
  1116.         struct axroute_tab *rp;
  1117.         struct ax_saverecord axbuf;
  1118.         struct iface *ifptable[ASY_MAX
  1119. #ifdef SCC
  1120.                                        + MAXSCC
  1121. #endif
  1122. #ifdef VANESSA
  1123.                                                 + VAN_MAX
  1124. #endif
  1125. #ifdef AXIP
  1126.                                                           + NAX25
  1127. #endif
  1128.                                                                  ];
  1129.  
  1130.         memset(ifptable,0,sizeof(ifptable));
  1131.  
  1132.         for (ifp = Ifaces; ifp; ifp = ifp->next) {
  1133.             if (ifp->output == ax_output) {
  1134.                 ifptable[ifp->niface] = ifp;
  1135.             }
  1136.         }
  1137.         while (fread(&axbuf,sizeof(struct ax_saverecord),1,fp)) {
  1138.             if (axbuf.time + Axholdtime < currtime) {
  1139.                 continue;
  1140.             }
  1141.             rp = axroute_tabptr(&axbuf.call, 1);
  1142.             if (axbuf.digi.call[0]) {
  1143.                 rp->digi = axroute_tabptr(&axbuf.digi, 1);
  1144.             }
  1145.             if (axbuf.dev >= 0 && axbuf.dev < Niface) {
  1146.                 rp->ifp = ifptable[axbuf.dev];
  1147.             }
  1148.             rp->time = axbuf.time;
  1149.         }
  1150.         Fclose(fp);
  1151.     }
  1152. #endif
  1153.  
  1154. #ifdef NETROM
  1155.     if(Nr_save) donrload();
  1156. #endif
  1157. }
  1158.  
  1159. int
  1160. dosavefile(int argc,char **argv,void *p)
  1161. {
  1162.   FILE *fp;
  1163.  
  1164. #ifdef NETROM
  1165.   extern int donrsave __ARGS((void));
  1166.   extern int Nr_save;
  1167. #endif
  1168.  
  1169.   if(uploadstatus) {
  1170.     return 0;
  1171.   }
  1172.   if((fp = Fopen(Iproutefile,WRITE_BINARY,0,1)) != NULLFILE) {
  1173.       struct ip_saverecord buf;
  1174.       struct route *rp;
  1175.  
  1176.       for(rp = Routes; rp != NULLROUTE; rp = rp->next) {
  1177.         if(rp->target == 0 || rp->flags >= RTPRIVATE || run_timer(&rp->timer)) {
  1178.           continue;
  1179.         }
  1180.         buf.target = rp->target;
  1181.         buf.bits = rp->bits;
  1182.         buf.gateway = (rp->gateway != 0) ? rp->gateway : 0xffffffffL;
  1183.         buf.niface = rp->iface->niface;
  1184.         buf.metric = rp->metric;
  1185.         buf.flags = rp->flags;
  1186.         fwrite(&buf,sizeof(struct ip_saverecord),1,fp);
  1187.       }
  1188.       Fclose(fp);
  1189.   }
  1190.  
  1191.   pwait(NULL);
  1192.  
  1193.   if((fp = Fopen(Arproutefile,WRITE_BINARY,0,1)) != NULLFILE) {
  1194.       struct arp_saverecord buf;
  1195.       struct arp_tab *p;
  1196.  
  1197.       fputc(ARP_FILE_VERSION, fp);
  1198.       for (p = Arp_tab; p; p = p->next) {
  1199.         if (p->hw_addr && p->state == ARP_VALID) {
  1200.           buf.ip_addr = p->ip_addr;
  1201.           buf.hardware = p->hardware;
  1202.           buf.flags = p->flags;
  1203.           buf.hwalen = p->hwalen;
  1204.           buf.pub = p->pub;
  1205.           fwrite(&buf,sizeof(struct arp_saverecord),1,fp);
  1206.           fwrite(p->hw_addr, p->hwalen, 1, fp);
  1207.         }
  1208.       }
  1209.       Fclose(fp);
  1210.   }
  1211.  
  1212.   pwait(NULL);
  1213.  
  1214. #ifdef AX25
  1215.   if((fp = Fopen(Axroutefile,WRITE_BINARY,0,1)) != NULLFILE) {
  1216.       struct ax_saverecord buf;
  1217.       struct axroute_tab *rp, *lp;
  1218.  
  1219.         for (lp = 0, rp = Axroute_tab; rp; ) {
  1220.           if (rp->time + Axholdtime >= currtime) {
  1221.             buf.call = rp->call;
  1222.             if (rp->digi) {
  1223.               buf.digi = rp->digi->call;
  1224.             } else {
  1225.               buf.digi.call[0] = '\0';
  1226.             }
  1227.             buf.dev = rp->ifp ? rp->ifp->niface : -1;
  1228.             buf.time = rp->time;
  1229.             fwrite(&buf,sizeof(struct ax_saverecord),1,fp);
  1230.             lp = rp;
  1231.             rp = rp->next;
  1232.           } else if (lp) {
  1233.             lp->next = rp->next;
  1234.             xfree(rp);
  1235.             rp = lp->next;
  1236.           } else {
  1237.             Axroute_tab = rp->next;
  1238.             xfree(rp);
  1239.             rp = Axroute_tab;
  1240.           }
  1241.         }
  1242.       Fclose(fp);
  1243.   }
  1244.  
  1245.   pwait(NULL);
  1246.  
  1247. #endif
  1248. #ifdef NETROM
  1249.   if(Nr_save) donrsave();
  1250. #endif
  1251.   return 0;
  1252. }
  1253.  
  1254. int
  1255. doattribute(int argc,char **argv,void *p)
  1256. {
  1257.     if(*argv[1] == 'm') {
  1258.         normal = 112;
  1259.         normalh = 15;
  1260.         normals = 112;
  1261.         invers = 240;
  1262.         red = 127;
  1263.         common = 7;
  1264.         panic = 143;
  1265.     } else {
  1266.         normal = NORMALL;
  1267.         normalh = NORMALH;
  1268.         normals = NORMALS;
  1269.         invers = INVERS;
  1270.         red = RED;
  1271.         common = COMMON;
  1272.         panic = PANIC;
  1273.     }
  1274.     return 0;
  1275. }
  1276.  
  1277. #ifdef RESETTIMER
  1278. static void near
  1279. inittim(void)
  1280. {
  1281.     outport(TIMCTRL,0x36);    /*Init Timer0 for sqarewavegeneration*/
  1282.     outport(TIMER0,0x50);
  1283.     outport(TIMER0,0x50);    /*Teilerfaktor für Timer0 0xffff*/
  1284.  
  1285.     outport(TIMCTRL,0x78);    /*Init Timer1 for squarewavegeneration*/
  1286.     outport(TIMER1,0xff);
  1287.     outport(TIMER1,0x0d);
  1288.  
  1289.     outport(TIMCTRL,0xb4);    /*Init Timer2 for sqarewavegeneration*/
  1290.     outport(TIMER2,0xff);
  1291.     outport(TIMER2,0x20);
  1292.  
  1293.  
  1294.     outport(IOCTRL,0x80);    /*Set all I/O-Ports to output im Mode0*/
  1295.     outport(IOCTRL,0x80);
  1296.     outport(PORTC,0xff);    /*activate Reset*/
  1297.  
  1298.     return;
  1299. }
  1300. #endif
  1301.  
  1302. static void near
  1303. cprint_timer(struct timer *timer)
  1304. {
  1305.     switch(timer->state) {
  1306.     case TIMER_RUN:
  1307.         cprintf("%3lu",read_timer(timer)/1000);
  1308.         break;
  1309.     case TIMER_STOP:
  1310.         cputs("  -");
  1311.         break;
  1312.     case TIMER_EXPIRE:
  1313.         cputs("  E");
  1314.         break;
  1315.     }
  1316.     cprintf("/%3lu│",dur_timer(timer)/1000);
  1317. }
  1318.  
  1319. static void
  1320. dostatustimer(void)
  1321. {
  1322.    if(!istate()) {                      /* return if in critical section */
  1323.       start_timer(&Statustimer);
  1324.       return;
  1325.    }
  1326.    alert(statp,(void *)1);              /* wake process                  */
  1327. }
  1328.  
  1329. void
  1330. statusline(int i,void *v1, void *v2)
  1331. {
  1332.     struct text_info str;
  1333.     struct time sttime;
  1334.     struct session *sp;
  1335.     struct usock *up;
  1336.     int s, flag;
  1337.     char size;
  1338.     extern int Attended;
  1339.     static unsigned min = 100;
  1340.  
  1341.     time(&currtime);
  1342.  
  1343.     statp = Curproc;
  1344.  
  1345.     Statustimer.func = (void (*)())dostatustimer; /* what to call on timeout*/
  1346.     Statustimer.arg = NULLCHAR;     /* dummy value                  */
  1347.     set_timer(&Statustimer,990);    /* set timer duration, appr. 1 sec*/
  1348. #ifdef MDEBUG
  1349.     strcpy(Statustimer.tname,"Status");
  1350. #endif
  1351.     start_timer(&Statustimer);
  1352.  
  1353.     for(; ;) {
  1354.         pwait(&sttime);
  1355.         stop_timer(&Statustimer);
  1356.  
  1357.         /*-----------------------------------------------------------*
  1358.          * get the current time                                      *
  1359.          * well, I don't think, one minute is a long time. between   *
  1360.          * minutes, the accuracy of the time is given by the NOS     *
  1361.          * timers. Every minute the various variables are synced     *
  1362.          * with the system time.                                     *
  1363.          *-----------------------------------------------------------*/
  1364.         gettime(&sttime);
  1365.         currtime++;                  /* increment system wide time_t */
  1366.  
  1367.         if(sttime.ti_min != min)   {
  1368.             time(&currtime);         /* resync system time           */
  1369.             min = sttime.ti_min;
  1370.             EMinute = min + sttime.ti_hour * 60;
  1371.  
  1372.             if(Eproc && EVwait == 0) {
  1373.                 alert(Eproc,(void *)EMinute);   /* wake event process */
  1374.             }
  1375.         }
  1376. #ifdef RESETTIMER
  1377.         outport(TIMER1,0xff);   /* Reset Timer */
  1378.         outport(TIMER1,0x0d);
  1379. #endif
  1380.  
  1381.         gettextinfo(&str);
  1382.         window(1,1,80,2);
  1383.         gotoxy(1,1);
  1384.  
  1385.         if((size = !availmem()) != 0) {
  1386.             textattr(panic);
  1387.             cputs(" PANIC ");
  1388.         } else {
  1389.             textattr(red);
  1390.             cputs(" WNOS5 ");
  1391.             textattr(normal);
  1392.         }
  1393.  
  1394.         if(Current->type == COMMAND || Current->type == TRACESESSION || size) {
  1395.             cprintf(" Coreleft%7lu",coreleft());
  1396.         } else {
  1397.             cprintf(" %-15.15s",Current->name);
  1398.         }
  1399.         s = -1;
  1400.         cprintf("│%-8s",(Current->type == FTP
  1401.           && (s = Current->cb.ftp->data) != -1)
  1402.           ? "FTP-DATA" : Sestypes[Current->type]);
  1403.  
  1404.         if((up = itop((s == -1) ? Current->s : s)) != NULLUSOCK) {
  1405.             switch(up->type) {
  1406.             default:
  1407.             case TYPE_RAW:      /* fix to bad status line */
  1408.                 goto line;      /* in ping session */
  1409.             case TYPE_TCP: {
  1410.                 struct tcb *tcb = up->cb.tcb;
  1411.  
  1412.                 if(tcb != NULLTCB) {
  1413.                     if(s == -1) {
  1414.                         cprintf("│Backoff%3u│TxQ%7u│RTT ",
  1415.                             tcb->backoff,tcb->sndcnt);
  1416.                     } else {
  1417.                         cprintf("│Rx%8lu│Tx%8lu│RTT ",
  1418.                             tcb->rcv.nxt - tcb->irs,tcb->snd.una - tcb->iss);
  1419.                     }
  1420.                     cprint_timer(&tcb->timer);
  1421.                     cputs("   ");
  1422.                 } else {
  1423.                     goto line;
  1424.                 }
  1425.                 break;
  1426.             }
  1427. #ifdef AX25
  1428.             case TYPE_AX25I: {
  1429.                 struct ax25_cb *axp = up->cb.ax25;
  1430.  
  1431.                 if(axp != NULLAX25) {
  1432.                     cprintf("│Retries%3d│Unack%5d│",axp->retries,axp->unack);
  1433.  
  1434.                     if(axp->dama) {
  1435.                         cprintf("DAMA-Tx%4d│",len_p(axp->txq));
  1436.                     } else {
  1437.                         cputs("T1  ");
  1438.                         cprint_timer(&axp->t1);
  1439.                     }
  1440.                     cputs(axp->remotebusy ? "RNR" : "   ");
  1441.                 } else {
  1442.                     goto line;
  1443.                 }
  1444.                 break;
  1445.             }
  1446. #endif
  1447. #ifdef NETROM
  1448.             case TYPE_NETROML4: {
  1449.                 struct nr4_cb *nr4 = up->cb.nr4;
  1450.  
  1451.                 if(nr4 != NULLNR4CB) {
  1452.                     cprintf("│Retries%3d│Unack%5d│SRTT%7ld│%s",
  1453.                         nr4->txmax,nr4->nbuffered,
  1454.                         nr4->srtt,nr4->choked ? "CHK" : "   ");
  1455.                 } else {
  1456.                     goto line;
  1457.                 }
  1458.                 break;
  1459.             }
  1460. #endif
  1461.             }
  1462.         } else {
  1463. line:
  1464.             cprintf("%31sttended",Attended ? "  A" : "Una");
  1465.         }
  1466.         if((flag = sttime.ti_sec & 1) != 0 && Current->rfile != NULLCHAR) {
  1467.             cputs("│R");
  1468.         } else if(!flag && Current->ufile != NULLCHAR) {
  1469.             cputs("│U");
  1470.         } else {
  1471.             cputs("│ ");
  1472.         }
  1473.         cprintf("│ %02d%c%02d ",sttime.ti_hour,flag ? ' ' : ':',sttime.ti_min);
  1474.  
  1475. /* 2nd line starts here */
  1476.         textattr(normals);
  1477.         for(sp = Sessions, s = 0; sp < &Sessions[Nsessions]; sp++) {
  1478.             if(sp->type == COMMAND || sp->type == TRACESESSION) {
  1479.                 continue;
  1480.             }
  1481.             s++;
  1482.             if(sp->type != FREE) {
  1483.                 if(socklen(sp->output,1)) {
  1484.                     textattr(invers);
  1485.                 }
  1486.                 cprintf(" %d:%s%s%s ",
  1487.                     s,
  1488.                     (sp->rfile == NULLCHAR) ? "" : "R:",
  1489.                     (sp->ufile == NULLCHAR) ? "" : "U:",
  1490.                     sp->name);
  1491.  
  1492.                 textattr(normals);
  1493.             }
  1494.         }
  1495.         clreol();
  1496.         window(str.winleft,str.wintop,str.winright,str.winbottom);
  1497.         textattr(common);
  1498.         gotoxy(str.curx,str.cury);
  1499.         start_timer(&Statustimer);
  1500.     }
  1501. }
  1502.